﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using GiMessServer.DatabaseDataSetTableAdapters;
using GiMessCommons;

namespace GiMessServer
{
    /// <summary>
    /// Clasa folosita pentru a lua diverse informatii din baza de date
    /// </summary>
    public static class Database
    {
        private static DataRow[] resultList;
        private static DataRow result;

        private static DatabaseDataSet dataSet;

        private static usersTableAdapter    usersAdapter;
        private static friendsTableAdapter  friendsAdapter;
        private static groupsTableAdapter   groupsAdapter;
        private static requestsTableAdapter requestsAdapter;

        private static DatabaseDataSet.usersDataTable    usersData;
        private static DatabaseDataSet.friendsDataTable  friendsData;
        private static DatabaseDataSet.groupsDataTable   groupsData;
        private static DatabaseDataSet.requestsDataTable requestsData;
        
        private static DataTable usersTable;
        private static DataTable friendsTable;
        private static DataTable groupsTable;


        /// <summary>
        /// Initializeaza clasa Database
        /// </summary>
        public static void Init()
        {
            dataSet = new DatabaseDataSet();

               usersAdapter = new usersTableAdapter  ();
             friendsAdapter = new friendsTableAdapter();
              groupsAdapter = new groupsTableAdapter ();
            requestsAdapter = new requestsTableAdapter();

               usersData = usersAdapter.GetData();
             friendsData = friendsAdapter.GetData();
              groupsData = groupsAdapter.GetData();
            requestsData = requestsAdapter.GetData();
            
            //nefolositoare 
            usersTable   = dataSet.Tables["users"];
            friendsTable = dataSet.Tables["friends"];
            groupsTable  = dataSet.Tables["groups"];
        }

        #region Database GetData

        //PENTRU ADI
        //TODO: de rescris selecturile 
        public static int GetUserId(string userName)
        {
            resultList = usersData.Select("user_name = '" + userName + "'");
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("No such user");
            return resultList[0].Field<int>("user_id");
        }

        public static string GetUserName(int userID)
        {
            resultList = usersData.Select("user_id = " + userID);
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("No user with specified userID");
            return resultList[0].Field<string>("user_name");
        }

        //TODO: in caz de user inexistent throw UserNotFoundException:DatabaseException?
        //TODO: de definit exceptie de baza DatabaseException?

        public static string GetUserPassword(string userName)
        {
            resultList = usersData.Select("user_name = '" + userName + "'");
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("Incorrect Username");
            return resultList[0].Field<string>("password");
        }

        public static string GetFullName(string userName)
        {
            resultList = usersData.Select("user_name = '" + userName + "'");
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("No such user");
            return resultList[0].Field<string>("first_name")+ " " + resultList[0].Field<string>("last_name");
        }

        public static string GetFirstName(string userName)
        {
            resultList = usersData.Select("user_name = '" + userName + "'");
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("No such user");
            return resultList[0].Field<string>("first_name");
        }

        public static string GetLastName(string userName)
        {
            resultList = usersData.Select("user_name = '" + userName + "'");
            if (resultList.GetLength(0) == 0)
                throw new UserNotFoundException("No such user");
            return resultList[0].Field<string>("last_name");
        }

        public static string GetStatus(int userID)
        {
            result = usersData.Select("user_id = " + userID)[0];
            return result.Field<string>("status");
        }

        public static string GetAvatar(int userID)
        {
            result = usersData.Select("user_id = " + userID)[0];
            return result.Field<string>("avatar");
        }

        public static string GetAvatar(string userName)
        {
            result = usersData.Select("user_name = '" + userName + "'")[0];
            return result.Field<string>("avatar");
        }

        public static bool GetOnlineStatus(int userID)
        {
            result = usersData.Select("user_id = " + userID)[0];
            return result.Field<bool>("online");
        }

        public static int GetGroupId(string groupName, int groupOwner)
        {
            result = groupsData.Select("group_name = '" + groupName + "' and group_owner = " + groupOwner)[0];
            return result.Field<int>("group_id");
        }

        public static string GetGroupName(int groupID)
        {
            result = groupsData.Select("group_id = " + groupID)[0];
            return result.Field<string>("group_name");
        }

        //TODO mai putine queriuri
        public static UserFriend[] GetUserList(int userID)
        {
            DataRow[]    friends;
            UserFriend[] friendsList;
            
            friends = friendsData.Select("user_id = '" + userID + "'");
            friendsList = new UserFriend[friends.Length];

            for (int i = 0; i < friends.Length; i++)
            {
                friendsList[i] = new UserFriend();
                friendsList[i].UserID  = (int)friends[i]["friend_id"];
                friendsList[i].GroupID = (int)friends[i]["group_id"];
            }

            for (int i = 0; i < friends.Length; i++)
            {
                friendsList[i].Username  = GetUserName (friendsList[i].UserID);
                friendsList[i].FirstName = GetFirstName(friendsList[i].Username);
                friendsList[i].LastName  = GetLastName (friendsList[i].Username);
                friendsList[i].Group     = GetGroupName(friendsList[i].GroupID);
                friendsList[i].Status    = GetStatus   (friendsList[i].UserID);
                friendsList[i].Avatar    = GetAvatar   (friendsList[i].UserID);
                friendsList[i].Online    = GetOnlineStatus(friendsList[i].UserID);
            }

            return friendsList;
        }

        public static UserFriend[] GetUserList(string username)
        {
            return GetUserList(GetUserId(username));
        }

        public static string[] GetUserGroups(int userID)
        {
            DataRow[] groups;
             string[] groupNames;

            groups = groupsData.Select("group_owner = '" + userID + "'");

            groupNames = new string[groups.Length];

            for (int i = 0; i < groups.Length; i++)
                groupNames[i] = groups[i].Field<string>("group_name");

            return groupNames;
        }

        public static string[] GetUserGroups(string username)
        {
            return GetUserGroups(GetUserId(username));
        }

        #endregion

        #region Database SetData

        public static void SetOnlineStatus(int userID, bool online)
        {
            result = usersData.Select("user_id = " + userID)[0];
            result["online"] = online;

            usersData.AcceptChanges();
        }

        public static void SetOnlineStatus(string userName, bool online)
        {
            result = usersData.Select("user_name = '" + userName + "'")[0];
            result["online"] = online;

            usersData.AcceptChanges();
        }

        public static void SetStatus(int userID, string status)
        {
            result = usersData.Select("user_id = " + userID)[0];
            result["status"] = status;

            usersData.AcceptChanges();
        }

        public static void SetStatus(string userName, string status)
        {
            result = usersData.Select("user_name = '" + userName + "'")[0];
            result["status"] = status;

            usersData.AcceptChanges();
        }

        public static void SetAvatar(string userName, string avatarHash)
        {
            result = usersData.Select("user_name = '" + userName + "'")[0];
            result["avatar"] = avatarHash;

            usersData.AcceptChanges();
        }

        public static void AddUser(string userName, string password, string firstName, string lastName, string email)
        {
            DatabaseDataSet.usersRow newUserRow = usersData.NewusersRow();

            newUserRow.user_name  = userName;
            newUserRow.password   = password;
            newUserRow.first_name = firstName;
            newUserRow.last_name  = lastName;
            newUserRow.email      = email;
            newUserRow.online     = false;
            newUserRow.avatar     = "";
            newUserRow.friend_requests = 0;

            usersData.AddusersRow(newUserRow);
            usersData.AcceptChanges();

            AddGroup(userName, "Friends");
        }

        public static void AddGroup(string userName, string groupName)
        {
            DatabaseDataSet.groupsRow newGroupRow = groupsData.NewgroupsRow();

            newGroupRow.group_name  = groupName;
            newGroupRow.group_owner = GetUserId(userName);
            
            groupsData.AddgroupsRow(newGroupRow);
            groupsData.AcceptChanges();
        }

        #endregion

        public static void DeleteFriend(string userName, string friend)
        {
            int userID   = GetUserId(userName);
            int friendID = GetUserId(friend);

            DataRow[] friends;

            friends = friendsData.Select("user_id = '" + userID + "' and friend_id='" + friendID + "'");
            friendsData.RemovefriendsRow((DatabaseDataSet.friendsRow)friends[0]);
        }

        public static void MoveFriend(string userName, string friend, string groupName)
        {
            int userId   = GetUserId(userName);
            int friendId = GetUserId(friend);
            int groupId  = GetGroupId(groupName, userId);

            DataRow friends;

            friends = friendsData.Select("user_id = '" + userId + "' and friend_id='" + friendId + "'")[0];

            friends["group_id"] = groupId;

            friendsData.AcceptChanges();
        }

        public static void GroupRename(string userName, string oldName, string newName)
        {
            int userId = GetUserId(userName);

            DataRow group;

            group = groupsData.Select("group_name = '" + oldName + "' AND group_owner = " + userId)[0];

            group["group_name"] = newName;

            groupsData.AcceptChanges();
        }

        public static void AddFriendRequest(string userName, string friend, string group)
        {
            int userId   = GetUserId(userName);
            int friendId = GetUserId(friend);
            int groupId  = GetGroupId(group, userId);

            var requestRow = requestsData.NewrequestsRow();

            requestRow.user_id   = userId;
            requestRow.friend_id = friendId;
            requestRow.group_id  = groupId;

            requestsData.AddrequestsRow(requestRow);
            requestsData.AcceptChanges();
        }

        public static string[] GetFriendRequests(string userName)
        {
             string[] ret;
            DataRow[] requests;

            int userId = GetUserId(userName);

            requests = requestsData.Select("friend_id = " + userId + " and accepted = NULL");

            ret = new string[requests.Length];

            for (int i = 0; i < requests.Length; i++)
            {
                ret[i] = GetUserName(requests[i].Field<int>("user_id"));
            }

            return ret;
        }

        public static void HandleFriendRequest(string friend, string username, bool accepted)
        {
            DataRow[] requests;

            int friendId = GetUserId(friend);
            int userId   = GetUserId(username);

            requests = requestsData.Select("user_id = " + userId + " and friend_id = " + friendId);
            //defapt e un singur request
            for (int i = 0; i < requests.Length; i++)
            {
                requests[i]["accepted"] = accepted;
                if (accepted)
                    AddUserFriend(userId, friendId, requests[i].Field<int>("group_id"));
            }
        }

        public static string GetRequestGroupName(string friend, string username)
        {
            DataRow[] requests;

            int friendId = GetUserId(friend);
            int userId = GetUserId(username);

            requests = requestsData.Select("user_id = " + userId + " and friend_id = " + friendId + " and accepted = True");
            for (int i = 0; i < requests.Length; i++)
            {
                return GetGroupName(requests[i].Field<int>("group_id"));
            }

            return null;
        }

        private static void AddUserFriend(int userId, int friendId, int groupId)
        {
            var friendRow = friendsData.NewfriendsRow();

            friendRow.user_id   = userId;
            friendRow.friend_id = friendId;
            friendRow.group_id  = groupId;

            friendsData.AddfriendsRow(friendRow);
            friendsData.AcceptChanges();
        }

        internal static string GetStatus(string userName)
        {
            return GetStatus(GetUserId(userName));
        }

        internal static object GetOnlineStatus(string userName)
        {
            return GetOnlineStatus(GetUserId(userName));
        }
    }
}
